Release 10.1A: OpenEdge Getting Started:
Object-oriented Programming


Assignment and the CAST function

As described in the previous section, you can assign a source object reference to a target object reference if the target object reference is defined as the same class, a super class, or an interface of the source object. When the target object reference is for a super class or interface an implicit cast is done by Progress at run time. The word cast, as used in object-oriented terminology, can be compared to the cast of a play, in which each actor is assigned a role. When you program with classes, each reference to an object must identify the role that the object is required to play, as identified by its class type. The compiler verifies that no object reference is allowed to act contrary to its assigned role and access a method or data member not defined by its class type.

However, sometimes you might want to restrict the use of an object reference to a subset of the methods and data members defined by its class. When you use an object reference to a super class that actually points to an instance of one of its subclasses, you are then restricting object access to the methods and data members defined by the super class, even though the object instance might actually contain additional subclass methods and data members. Thus, restricting an object reference to the role of a super class assures that the reference can satisfy the minimum access requirements provided for the object by the super class while at the same time preventing any reference to the additional subclass state and behavior that the object might contain. In other words, using a super class object reference provides an additional level of information hiding for the subclass instance.

Similarly, an interface defines at least some of the methods that a class implements. Thus, assigning an object reference from a class to an interface that the class type implements assures that the object reference enforces access only to implemented methods in the class that are defined by the specified interface.

Progress permits all of these assignments from a subclass reference to a super class reference and from an interface reference to an implementing-class reference, because the very definition of a subclass or implementing class guarantees that PUBLIC data members and methods provided by the respective super class and interface object references will work. For example, refer to the following class hierarchy:

Progress.Lang.Object                  <--- Top of hierarchy 
    acme.myObjs.Common.CommonObj 
        acme.myObjs.CustObj 
            acme.myObjs.NECustomer    <--- Bottom of hierarchy 

You can assign an acme.myObjs.NECustomer object reference to either an acme.myObjs.CustObj, acme.myObjs.Common.CommonObj or Progress.Lang.Object object reference. You can also assign an acme.myObjs.CustObj object reference to an acme.myObjs.Common.CommonObj or Progress.Lang.Object object reference.

Sometimes it is necessary to cast downward—that is, to take an object reference for a super class or interface in a class hierarchy and assign it to an object reference defined for a subclass or interface-implementing class further down the class hierarchy. As noted, the compiler will not do this implicitly when you perform an assignment or pass a parameter, because it cannot verify that references to the object will all be valid. Therefore, you must cast an object reference downward explicitly using the CAST function. In addition, you cannot assign an object reference for an interface to an object reference for a class, even if the class implements the interface. To do this you must also use the CAST function.

You can only cast an object reference downward when the object was originally instantiated as the target class or one of its subclasses. This means that you must know that a super class object reference, at run time, is really an object reference to a subclass or that an interface object reference is really an object reference to an interface-implementing class.

Casting tells the compiler to trust your judgement and allow the downward cast within the specified class hierarchy. However, Progress checks at run time to ensure that a cast is valid. For example, if a super class object reference is not referring to an instance of the specified subclass, Progress returns a run-time error. This means that when you use the CAST function, you are bypassing some of the compiler's checks for validity of object references. This increases the flexibility of how you can assemble different classes and let them interoperate, but with your increased responsibility for making sure that all types are valid at run time.

You can thus use the CAST function wherever an object reference is permitted:

Syntax descriptions for each of these uses of the CAST function follow.

This is the syntax for the CAST function used to assign one object reference to another:

Syntax
target-object-reference = CAST ( object-reference , target-type-name ) 

This is the syntax for the CAST function used to pass an INPUT object reference parameter:

Syntax
 routine-name ( [ INPUT ] CAST ( object-reference , target-type-name ) ) 

This is the syntax for the CAST function used to cast an object reference for a method call:

Syntax
CAST ( object-reference , target-type-name ) : method-name ( ... ) 

Element descriptions for these syntax diagrams follow:

target-object-reference

A destination object reference, typically to one of the following:

object-reference

A source object reference, typically to a super class or interface of target-object-reference. This can be a variable or it can be a temp-table field defined as Progress.Lang.Object. At run time, Progress verifies that object-reference in fact refers to an instance of the specified target-type-name.

target-type-name

A quoted string specifying the target class type name for the cast. This class type name must be the same as the class type name used to define target-object-reference or a subclass of the defining type name.

routine-name

The name of any procedure, user-defined function, or method that takes an INPUT object reference parameter.

method-name

The name of a method implemented by the class specified by target-type-name. The compiler verifies that method-name is a valid method defined in target-type-name and that the parameters ((...)) are valid.

Casting an object reference assignment

For an example of assigning an object reference using the CAST function, see the "Defining an object reference as a field in a temp-table" section.

Casting an object reference parameter

The following sample classes are use by the following examples to demonstrate the use of the CAST function to pass INPUT object reference parameters. The first sample class is a super class that defines nothing:

CLASS SuperClass: 
END CLASS. 

The next sample class is a subclass that defines its own method, subClassMethod( ):

CLASS SubClass INHERITS SuperClass: 
    METHOD PUBLIC VOID subclassMethod ( ): 
    END METHOD. 
END CLASS. 

Progress does not, by default, allow an object reference of SuperClass to be used as an instance of SubClass. For example, if you try to execute subClassMethod( ) using the object reference to SuperClass, the method cannot be found. However, if you know that an object reference to SuperClass in reality points to an instance of SubClass, you can cast the reference as SubClass to use it.

The following example demonstrates the use of the CAST function to pass an INPUT object reference parameter. The Main container class defines an object reference (mySuper) for the super class and a method (subParmMethod( )) that expects an object parameter of type SubClass, as shown:

CLASS Main: 
     
    DEFINE PRIVATE VARIABLE mySuper AS CLASS SuperClass NO-UNDO. 
    CONSTRUCTOR PUBLIC Main ( ): 
        mySuper = NEW SubClass ( ). 
        subParmMethod (INPUT CAST(mySuper, "SubClass")). 
    END CONSTRUCTOR. 
    METHOD PRIVATE VOID subParmMethod  
            (INPUT myLocalSubClass AS CLASS SubClass): 
        myLocalSubClass:subClassMethod( ). 
    END METHOD. 
END CLASS. 

In the previous example, the constructor instantiates a SubClass object, but assigns it to the SuperClass object reference. Using the CAST function, the constructor then invokes subParmMethod( ), passing the object reference as the SubClass parameter the method expects and that it actually is. The subParmMethod( ) method then invokes the subClassMethod( ) method on the passed object reference.

Casting an object reference to invoke a method

The following example shows an alternative Main class used to access the sample classes SuperClass and SubClass defined in the previous example, this time to demonstrate the use of the CAST function to cast an object reference for a method call:

CLASS Main: 
      
    DEFINE PRIVATE VARIABLE mySuper AS CLASS SuperClass NO-UNDO. 
    CONSTRUCTOR PUBLIC Main ( ): 
        mySuper = NEW SubClass ( ). 
        CAST(mySuper, "SubClass"):subClassMethod ( ).  
    END CONSTRUCTOR. 
END CLASS. 

In the previous example, the constructor sets the SuperClass object reference to a new SubClass instance, then invokes subClassMethod( ) on the SubClass instance by casting the SuperClass object reference to SubClass.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095